package com.deneme;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.logging.Logger;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceException;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.users.User;

@SuppressWarnings("serial")
public class UserData implements Serializable {
	private static Logger logger = Logger.getLogger(UserData.class.getName());
	private String userId; // id of user
	private ArrayList<BlobKey> imageKeys; // blob keys corresponding to uploaded pictures
	private ArrayList<BlobKey> imagesToDelete; // blob keys of smaller images to be deleted periodically
	private ArrayList<String> puzzleKeys; // keys assocated with saved puzzles
	private User user; // user object obtained from Google

	public UserData(String userId) {
		this.userId = userId;
	}

	public String getUserId() {
		return userId;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
		save();
	}

	public ArrayList<BlobKey> getImageKeys() {
		return imageKeys;
	}

	public void setImageKeys(ArrayList<BlobKey> keys) {
		imageKeys = keys;
		save();
	}
	
	public void addImageKey(BlobKey newkey) {
		if (imageKeys == null) {
			imageKeys = new ArrayList<BlobKey>();
		}
		imageKeys.add(newkey);
		save();
	}

	public ArrayList<BlobKey> getImagesToDelete() {
		return imagesToDelete;
	}

	public void setImagesToDelete(ArrayList<BlobKey> keys) {
		imagesToDelete = keys;
		save();
	}
	
	public void addImageToDelete(BlobKey newkey) {
		if (imagesToDelete == null) {
			imagesToDelete = new ArrayList<BlobKey>();
		}
		imagesToDelete.add(newkey);
		save();
	}

	public ArrayList<String> getPuzzleKeys() {
		return puzzleKeys;
	}

	public void setPuzzleKeys(ArrayList<String> savedPuzzleKeys) {
		puzzleKeys = savedPuzzleKeys;
		save();
	}
	
	public void addPuzzleKey(String newPuzzleKey) {
		if (puzzleKeys == null) {
			puzzleKeys = new ArrayList<String>();
		}
		puzzleKeys.add(newPuzzleKey);
		save();
	}

	@SuppressWarnings("unchecked")
	public static UserData getDataForUser(User myUser) {
//		System.out.println("Getting data for user: " + myUser.getUserId());
		Entity userEntity = null;
		String cacheKey = "UserData:" + myUser.getUserId();
		try {
			MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
			if (memcache.contains(cacheKey)) {
//				System.out.println("CACHE HIT");
				userEntity = (Entity) memcache.get(cacheKey);
				return entityToData(userEntity);
			}
//			System.out.println("CACHE MISS");
			// If the UserPrefs object isn't in memcache,
			// fall through to the datastore.
		} catch (MemcacheServiceException e) {
			// If there is a problem with the cache,
			// fall through to the datastore.
		}
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Key datakey = KeyFactory.createKey("UserData", myUser.getUserId());
		UserData data = null;
		try {
			Query query = new Query("UserData", datakey);
			userEntity = datastore.prepare(query).asSingleEntity();
			if(userEntity != null) {
				try {
					MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
					memcache.put(cacheKey, userEntity);
				} catch (MemcacheServiceException e) {
					// Ignore cache problems, nothing we can do.
				}
				data = entityToData(userEntity);
			} else {
//				System.out.println("MAKING A NEW USER!  OH NOES");
				data = new UserData(myUser.getUserId());
				data.setUser(myUser);
				data.save();
			}
		} finally {
		}
//		System.out.println("Hitting the final return");
		return data;
	}
	
	/* This function saves the UserData to the memcache and datastore */
	public void save() {
		/* create keys and get appropriate storage services */
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Key datakey = KeyFactory.createKey("UserData", this.userId);

		String cacheKey = "UserData:" + this.userId;
		MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();

		/* try to find the entry in memcache */
		Entity data = null;
		if (memcache.contains(cacheKey)) {
			data = (Entity) memcache.get(cacheKey);
		}
		/* if it's not there, try to find it in datastore */
		if (data == null) {
			Query query = new Query("UserData", datakey);
			data = datastore.prepare(query).asSingleEntity();
		}
		/* if it's not there create a new object */
		if(data == null) {
			data = new Entity("UserData", datakey);
		}
		/* update entity fields */
		data.setProperty("UserId", this.userId);
		data.setProperty("User", this.user);
		data.setProperty("BlobKeys", this.imageKeys);
		data.setProperty("DeleteList", this.imagesToDelete);
		data.setProperty("Puzzles", this.puzzleKeys);
		
		/*save in datastore */
		datastore.put(data);
		
		/* save in memcache */
		try {
			memcache.put(cacheKey, data);
		} catch (MemcacheServiceException e) {
			// Ignore cache problems, nothing we can do.
		}
	}
	
	/* this function converts an entity to a UserData object */
	public static UserData entityToData(Entity entity) {
		UserData user = new UserData((String)entity.getProperty("UserId"));
		user.setUser((User)entity.getProperty("User"));
		user.setImageKeys((ArrayList<BlobKey>)entity.getProperty("BlobKeys"));
		user.setImagesToDelete((ArrayList<BlobKey>)entity.getProperty("DeleteList"));
		user.setPuzzleKeys((ArrayList<String>)entity.getProperty("Puzzles"));
		return user;
	}
}
